<template>
  <div class="dictionary-authorization">
    <div class="content">
      <div class="top">
        字典授权：
        <je-select
          v-model:value="SQLValue"
          :style="{ marginRight: '100px' }"
          :options="SQLOptions"
          :allow-clear="false"
        ></je-select>
        授权范围：
        <je-select
          v-model:value="authorizationValue"
          :disabled="disabled"
          :options="authorizationOptions"
          :allow-clear="false"
          @change="changeEvent"
        ></je-select>
      </div>
      <div class="warp">
        <div class="left">
          <div class="title">{{ title }}</div>
          <div class="panel">
            <je-tree
              ref="treeview"
              class="table-treeView"
              :search="false"
              :tree-config="{
                trigger: 'cell-dblclick',
                rowField: 'id',
                parentField: 'parent',
                expandAll: true,
              }"
              :checkbox-config="{
                checkField: 'checked',
                checkMethod: ({ row }) => {
                  return !disabled && row.bean.ROLE_TYPE_CODE !== 'folder';
                },
                checkStrictly: true,
                cascadeChild: false,
                cascadeParent: false,
              }"
              :loading="loading"
              size="mini"
              :data="treeData"
              multiple
              @checkbox-change="handlerSelect"
            >
              <template #nodeIcon="{ row }">
                <i
                  v-if="row.bean.ROLE_TYPE_CODE === 'folder' && row.children.length === 0"
                  class="is--folder fas fa-folder"
                ></i>
              </template>
            </je-tree>
          </div>
        </div>
        <div class="middle">
          <div class="title">字典</div>
          <div class="list">
            <template v-if="funcDicList.length > 0">
              <div
                v-for="item in funcDicList"
                :key="item.code"
                class="list-tiem"
                :class="{ active: currentClickCode === item.code }"
                @click="dicClickEvent(item)"
              >
                {{ item.text }}&nbsp;&nbsp;&nbsp;
                <i
                  v-if="hasCrise.includes(rowId) && hasCrise.includes(item.code)"
                  :style="{ color: '#5c8dff' }"
                  class="fas fa-circle"
                ></i>
              </div>
            </template>
            <je-loading v-if="loadMsak" />
            <div v-if="funcDicList.length === 0 && !loadMsak" class="null">暂无数据</div>
          </div>
        </div>
        <div class="right">
          <div class="title">字典项</div>
          <div class="panel">
            <template v-if="funcDicItemList.length > 0">
              <div
                v-for="item in funcDicItemList"
                :key="item.id"
                class="list-tiem"
                @click="itemsClick(item.checked, item.id)"
              >
                <je-switch v-model:value="item.checked" mode="checkbox" :disabled="disabled" />
                <div class="word">{{ item.text }}</div>
              </div>
            </template>
            <je-loading v-if="loadMsak" />
            <div v-if="funcDicItemList.length === 0 && !loadMsak" class="null">暂无数据</div>
          </div>
        </div>
      </div>
    </div>
    <div class="footer">
      <je-button type="primary" :disabled="btnDisabled" class="btn" @click="save"
        >保存刷新</je-button
      >
      <je-button class="btn" :disabled="disabled || btnDisabled" @click="reset">恢复数据</je-button>
      <je-button class="btn" @click="closeEvent">关闭</je-button>
    </div>
  </div>
</template>

<script>
  import { defineComponent, onMounted, ref, watch } from 'vue';

  import { Button, Modal, Select, Tree, Loading } from '@jecloud/ui';

  import {
    getPremDataApi,
    loadDepartmentTreeApi,
    loadOrgApi,
    doSaveApi,
    loadRoleTreeApi,
  } from '@/api/authorization';

  import { useDialog } from '@/hooks/use-dialog';

  import {
    JE_DATAAUTHORITY_DAAUTHORIZATIONOPTIONS,
    JE_DATAAUTHORITY_DASQLOOPTIONS,
  } from '@/helper/constant';

  export default defineComponent({
    name: 'DictionaryAuthorization',
    components: {
      JeButton: Button,
      JeSelect: Select,
      JeTree: Tree,
      JeLoading: Loading,
    },
    props: {
      currentFuncId: {
        type: String,
        default: '',
      },
      currentFuncCode: {
        type: String,
        default: '',
      },
      parentModal: String,
    },
    emits: ['isChange'],
    setup(props, { emit }) {
      const treeData = ref([]);
      const treeview = ref('treeview');
      const loading = ref(false);

      const title = ref('角色权限'); // 标题
      const funcDicList = ref([]); // 字典数组
      const funcDicItemList = ref([]); // 字典项数组

      const SQLValue = ref('0'); // SQL值
      // SQL选项
      const SQLOptions = JE_DATAAUTHORITY_DASQLOOPTIONS;
      const authorizationValue = ref('0'); // 授权值
      // 授权选项data
      const authorizationOptions = JE_DATAAUTHORITY_DAAUTHORIZATIONOPTIONS;

      const disabled = ref(true); // 展示有功能授权的所有角色值

      // 页面所有数据
      const allData = ref([]);
      // 传参
      const payloadData = ref({
        dictCanCelAuthDeptList: [],
        dictCanCelAuthOrgList: [],
        dictCanCelAuthRoleList: [],
      });
      let meta = []; //对比项
      let metaOpen = '0'; //对比项
      const btnDisabled = ref(false); // 按钮禁用
      const loadMsak = ref(false); // 字典遮罩层

      // 请求对象
      const apiObj = {
        loadRoleTree: loadRoleTreeApi(),
        loadDeptTree: loadDepartmentTreeApi(),
        loadOrgTree: loadOrgApi({ excludeDepartment: '1' }),
      };

      // 切换得到左侧树
      const getTreeData = (param) => {
        restAllData();
        loading.value = true;
        // 根据参数调用相应的接口
        apiObj[param].then((res) => {
          treeData.value = res.children;
          loading.value = false;
          setTimeout(() => {
            // 展开
            treeData.value.forEach((item) => {
              // 展开tree
              const row = treeview.value.getRowById(item.id);
              treeview.value.setTreeExpand(row, true);
              btnDisabled.value = false;
            });
          }, 200);
        });
      };

      // 选择授权范围
      const changeEvent = (e) => {
        if (e === '0') {
          // 角色
          title.value = '角色权限';
          getTreeData('loadRoleTree');
        } else if (e === '1') {
          // 部门
          title.value = '部门权限';
          getTreeData('loadDeptTree');
        } else if (e === '2') {
          // 机构
          title.value = '机构权限';
          getTreeData('loadOrgTree');
        }
      };

      const funcId = ref('');
      const funcCode = ref('');

      // 保存
      const save = () => {
        // 数据改变在进行后续操作
        if (isChange()) return Modal.notice('无数据操作!', 'info');
        btnDisabled.value = true;
        allData.value = [];
        // 获取数据
        getSaveData();
        doSaveApi({
          tableCode: 'JE_CORE_FUNCPERM',
          FUNCPERM_FUNCINFO_CODE: funcCode.value,
          FUNCPERM_FUNCINFO_ID: funcId.value,
          FUNCPERM_TYPE: 'dictionaryAuth',
          FUNCPERM_ON_OFF: SQLValue.value,
          FUNCPERM_CONFIG: JSON.stringify(payloadData.value),
        }).then((res) => {
          Modal.notice(res.message, 'success');
          btnDisabled.value = false;
          // 更新数据
          GetPremData('save');
          setTimeout(() => {
            // 对照组重新赋值
            if (SQLValue.value) {
              metaOpen = JSON.parse(JSON.stringify(SQLValue.value));
            }
            meta = JSON.parse(JSON.stringify(metaList));
          }, 200);
        });
      };

      const childCode = ref(''); // 字典项结果
      const code = ref(''); // 字典结果
      // 得到保存数据
      const getSaveData = () => {
        // 获取所有选中数据
        const nowData = treeview.value.getCheckboxRecords(true);
        nowData.forEach((item) => {
          const obj = {};
          const arr = [];
          // 字典数组赋值
          funcDicList.value.forEach((item) => {
            const list = [];
            const obj1 = {};
            // 得到所有值0的id
            item.item.forEach((td) => {
              if (td.checked === '0') {
                list.push(td.id);
              }
            });
            // 转化成字符串并将其赋值给childCode
            childCode.value = list.join(',');
            obj1['childCode'] = childCode.value;
            obj1['code'] = item.code;
            // 到一个对象数组，键为childCode和code
            arr.push(obj1);
          });
          obj['dictList'] = arr;
          obj['id'] = item.id;
          // 将其赋值给当前页面数据
          allData.value.push(obj);
        });
        // 置空
        payloadData.value.dictCanCelAuthDeptList = [];
        payloadData.value.dictCanCelAuthOrgList = [];
        payloadData.value.dictCanCelAuthRoleList = [];
        // 赋值
        if (title.value === '角色权限') {
          payloadData.value.dictCanCelAuthRoleList = JSON.parse(JSON.stringify(allData.value));
        } else if (title.value === '部门权限') {
          payloadData.value.dictCanCelAuthDeptList = JSON.parse(JSON.stringify(allData.value));
        } else {
          payloadData.value.dictCanCelAuthOrgList = JSON.parse(JSON.stringify(allData.value));
        }
      };

      // 获取字典项funcDicList.value
      const codeList = [];
      let metaList = []; // 未勾选项目
      let canlick = true; // list是否可点击
      let targetlist = [];
      let currentClickCode = ref('');
      // 字典列表点击事件
      const dicClickEvent = (res) => {
        // 但canlick为真才能继续操作
        if (canlick) return false;
        setTimeout(() => {
          // currentClickCode赋值
          currentClickCode.value = res.code;
          // 得到当前字典
          const arr = funcDicList.value.filter((item) => {
            return item.code === currentClickCode.value;
          });
          const data = arr[0];
          code.value = data.code;
          // 得到当前字典项
          funcDicItemList.value = data.item;
          // 当前字典项每一个加一个checked字段，并赋值'1'
          funcDicItemList.value.forEach((item) => {
            codeList.push(item.id);
            item['checked'] = '1';
          });
          // 得到勾选项数组
          targetlist = codeList.filter((item) => {
            return !metaList?.includes(item);
          });
          // 回显
          funcDicItemList.value.forEach((item) => {
            // 勾选checked赋值为1，否则赋值为0
            if (targetlist.includes(item.id)) {
              item['checked'] = '1';
            } else {
              item['checked'] = '0';
            }
          });
          // 字典项赋值
          funcDicItemList.value.forEach((item) => {
            // 当为字典点击的code才赋值
            if (item.code === currentClickCode.value) {
              item.item = funcDicItemList.value;
            }
          });
        }, 100);
      };

      // 回显
      onMounted(() => {
        funcId.value = props.currentFuncId;
        funcCode.value = props.currentFuncCode;
        loading.value = true;
        GetPremData();
      });

      const rowId = ref('');
      // 点击事件字典
      let row1 = [];
      const handlerSelect = ({ row }) => {
        // 文件夹不可点击
        if (row.bean.ROLE_TYPE_CODE === 'folder') {
          return false;
        }
        // 字典项数组清空
        funcDicItemList.value = [];
        // currentClickCode.value = '';
        // 激活字典的操作
        canlick = true;
        if (!row1.includes(row.id)) {
          // 没选中
          row1.push(row.id);
          // 小蓝点代表有操作
          hasCrise.value.push(row1[0]);
        } else {
          // 当此前有保存值
          if (isClearAll.value === true) {
            const index = row1.findIndex((item) => {
              return item === row.id;
            });
            // 删除所选项
            row1.splice(index, 1);
            // 重新给hasCrise赋值
            hasCrise.value = [];
            if (row1[0]) {
              hasCrise.value.push(row1[0]);
            }
          } else {
            // 此前没有保存值，且是取消第一个勾选的
            if (row.id === row1[0]) {
              const index = row1.findIndex((item) => {
                return item === row.id;
              });
              row1.splice(index, 1);
              // 重置对比项
              metaList = [];
              meta = JSON.parse(JSON.stringify(metaList));
              // 重新给hasCrise赋值
              hasCrise.value = [];
              if (row1[0]) {
                hasCrise.value.push(row1[0]);
              }
            } else {
              // 直接删除
              const index = row1.findIndex((item) => {
                return item === row.id;
              });
              row1.splice(index, 1);
            }
          }
        }
        // 右侧tree有勾选,字典和字典项才能进行操作
        row1.length > 0 ? (canlick = false) : (canlick = true);
        rowId.value = row1[0];
        setResultBytitle();
      };
      // 根据哪个页面赋值
      const setResultBytitle = () => {
        // 根据条件渲染不同的页面
        if (title.value === '角色权限') {
          setResult('dictCanCelAuthRoleList', rowId.value);
        } else if (title.value === '部门权限') {
          setResult('dictCanCelAuthDeptList', rowId.value);
        } else {
          setResult('dictCanCelAuthOrgList', rowId.value);
        }
      };

      // 点击字典项
      const itemsClick = (val, sid) => {
        // 选中
        if (val === '0') {
          const index = metaList.findIndex((item) => {
            return item === sid;
          });
          metaList.splice(index, 1);
        } else {
          // 取消选中
          if (!metaList.includes(sid)) {
            metaList.push(sid);
          }
        }
        // 得到当前字典项数组
        const arr = funcDicList.value.filter((item) => {
          return item.code === currentClickCode.value;
        });
        // 得到未选中的字典项数组
        const arr1 = arr[0]?.item?.filter((item) => {
          return item.checked === '0';
        });
        // 当前只有一个选中且，最后一个也将取消
        if (arr1.length === arr[0]?.item?.length - 1 && val === '1') {
          Modal.alert('全不选择，代表选择所有权限', 'info');
          setTimeout(() => {
            const myArr = [];
            arr[0]?.item?.forEach((item) => {
              item.checked = '1';
              myArr.push(item.id);
            });
            // 全选
            myArr.forEach((id) => {
              metaList = metaList.filter((td) => {
                return td !== id;
              });
            });
          }, 0);
        }
        setTimeout(() => {
          // 勾选项数组
          const arr2 = arr[0]?.item?.filter((item) => {
            return item.checked === '1';
          });
          // 放入蓝点数组
          if (arr2.length === arr[0]?.item?.length) {
            hasCrise.value = hasCrise.value.filter((item) => {
              return item !== currentClickCode.value;
            });
          } else {
            if (
              !hasCrise.value.includes(rowId.value) ||
              !hasCrise.value.includes(currentClickCode.value)
            ) {
              hasCrise.value.push(currentClickCode.value);
            }
          }
        }, 100);
      };

      // 回显值
      const GetPremData = (flag) => {
        // 字典遮罩层
        loadMsak.value = true;
        // 调用加载数据接口
        getPremDataApi({
          tableCode: 'JE_CORE_FUNCPERM',
          FUNCPERM_FUNCINFO_ID: funcId.value,
          FUNCPERM_TYPE: 'dictionaryAuth',
        }).then((res) => {
          loadMsak.value = false;
          loading.value = false;
          // 不存在flag才重新家在数据
          if (!flag) {
            treeData.value = res[0].values?.roleTree?.children;
          }
          btnDisabled.value = false;
          if (res[0]?.values) {
            // 赋值并给对照项赋值
            SQLValue.value = res[0]?.values?.FUNCPERM_ON_OFF || '0';
            if (SQLValue.value) {
              metaOpen = JSON.parse(JSON.stringify(SQLValue.value));
            }
            funcDicList.value = [];
            funcDicList.value = res[0]?.values?.dictList;
            if (res[0]?.values?.FUNCPERM_CONFIG) {
              payloadData.value = JSON.parse(res[0]?.values?.FUNCPERM_CONFIG);
            }
            // 获取对应字典
          }
          if (flag === 'save') {
            // reload
            setResultBytitle();
            selfDicClickEvent();
          }
          setTimeout(() => {
            // 展开
            treeData.value.forEach((item) => {
              const row = treeview.value.getRowById(item.id);
              treeview.value.setTreeExpand(row, true);
            });
          }, 130);
        });
      };
      // 模拟点击字典
      const selfDicClickEvent = () => {
        // 得到当前字典数组
        const data = funcDicList.value.filter((item) => {
          return item.code === currentClickCode.value;
        });
        if (data.length > 0) {
          dicClickEvent(data[0]);
        }
      };

      // 存在小小圆圈的对象
      const hasCrise = ref([]);

      const isClearAll = ref(false); // 是否清楚所有
      // 赋值
      const setResult = (target, id) => {
        // 得到当前数据
        const res = payloadData.value[target];
        // 返回是否为空
        res.length > 0 ? (isClearAll.value = true) : (isClearAll.value = false);
        // 得到字典项
        const result = res?.filter((item) => {
          return item.id === id;
        });
        // 勾选项
        if (currentClickCode.value) {
          setTimeout(() => {
            selfDicClickEvent();
          }, 250);
        }
        if (result?.length > 0) {
          // 此字典是否有值
          const isTure = result[0]?.dictList?.some((item) => {
            return item.childCode;
          });
          if (isTure) {
            result[0]?.dictList?.forEach((item) => {
              // 是否有小圆圈
              if (item.childCode && !hasCrise.value.includes(item.code)) {
                hasCrise.value.push(item.code);
              }
              const arr = item.childCode.split(',');
              metaList = metaList.concat(arr);
              metaList = metaList.filter((str) => !!str);
            });
            metaList = Array.from(new Set(metaList));
          } else {
            // 没有为空
            metaList = [];
          }
        } else {
          if (isClearAll.value) {
            // 返回没有值
            metaList = [];
          }
        }
        meta = JSON.parse(JSON.stringify(metaList)); // 重新赋值对照组
        // 是否打钩
        funcDicList.value.forEach((item) => {
          item.item.forEach((td) => {
            if (metaList.includes(td.id)) {
              td['checked'] = '0';
            } else {
              td['checked'] = '1';
            }
          });
        });
      };

      // 根据SQLValue值来控制是否可操作
      watch(
        () => SQLValue.value,
        (nv) => {
          disabled.value = nv === '0';
        },
        { immediate: true },
      );

      // 清空数据
      const restAllData = () => {
        allData.value = [];
        funcDicItemList.value = [];
        currentClickCode.value = '';
        canlick = true;
        hasCrise.value = [];
        row1 = [];
        rowId.value = '';
        metaList = [];
        treeview.value.reloadData(treeData);
      };

      // 对比是否的改变
      const isChange = () => {
        // 去重
        metaList = metaList.filter((str) => !!str);
        meta = meta.filter((str) => !!str);
        let res1 = true;
        let res2 = true;
        let bool3 = true;
        const res3 = metaOpen === SQLValue.value;
        const row1 = [];
        // 得到所有勾选项
        const nowData = treeview.value.getCheckboxRecords(true);
        nowData.forEach((item) => {
          row1.push(item.id);
        });
        if (nowData.length > 0) {
          // 两数组是否相同
          res1 = metaList.every((x) => {
            return meta.includes(x);
          });
          res2 = meta.every((x) => {
            return metaList.includes(x);
          });
          if (title.value === '角色权限') {
            bool3 = contrastData('dictCanCelAuthRoleList', bool3);
          } else if (title.value === '部门权限') {
            bool3 = contrastData('dictCanCelAuthDeptList', bool3);
          } else if (title.value === '机构权限') {
            bool3 = contrastData('dictCanCelAuthOrgList', bool3);
          }
        }
        return res1 && res2 && res3 && bool3;
      };
      // 新旧值对比
      const contrastData = (target, bool3) => {
        const arr = [];
        let bool = bool3;
        // 对比长度
        if (metaList.length > 0 && currentClickCode.value) {
          payloadData.value[target].forEach((item) => {
            arr.push(item.id);
          });
          // 是否有新增
          const resnew = row1.every((x) => {
            return arr.includes(x);
          });
          if (!resnew) {
            return (bool = false);
          }
          // 第一个勾选项的所有数据
          const result = payloadData.value[target].filter((item) => {
            return row1.includes(item.id);
          });
          // 所有勾选项是否跟第一个勾选项数据一致
          bool = result.every((item) => {
            let arr3 = [];
            item.dictList.forEach((td) => {
              if (td.childCode && !arr3.includes(td.childCode)) {
                arr3 = arr3.concat(td.childCode.split(','));
              }
            });
            const res1 = metaList.every((x) => {
              return arr3.includes(x);
            });
            const res2 = arr3.every((x) => {
              return metaList.includes(x);
            });
            return res1 && res2;
          });
        }
        return bool;
      };

      // 恢复数据
      const reset = () => {
        Modal.confirm('您确定要恢复数据吗？', () => {
          toReset();
        });
      };

      // 还原数据
      const toReset = () => {
        metaList = JSON.parse(JSON.stringify(meta));
        GetPremData('flag');
        setTimeout(() => {
          treeview.value.clearCheckboxRow();
          allData.value = [];
          funcDicItemList.value = [];
          currentClickCode.value = '';
          canlick = true;
          hasCrise.value = [];
          rowId.value = '';
          row1 = [];
        }, 200);
      };

      // 切换tab
      const changeTabCb = () => {
        setTimeout(() => {
          const flag = isChange();
          if (flag) return emit('isChange', flag);
          setTimeout(() => {
            // 弹框
            useDialog({ toReset, save, isDicOrRole: true });
          }, 0);
        }, 0);
      };

      // 关闭
      const closeEvent = () => {
        hasCrise.value = [];
        meta = [];
        metaOpen = '0';
        props.parentModal.close();
      };

      return {
        SQLValue,
        SQLOptions,
        authorizationValue,
        authorizationOptions,
        disabled,
        treeData,
        treeview,
        loading,
        title,
        funcDicList,
        funcDicItemList,
        currentClickCode,
        loadMsak,
        rowId,
        hasCrise,
        changeEvent,
        save,
        dicClickEvent,
        handlerSelect,
        reset,
        closeEvent,
        itemsClick,
        changeTabCb,
      };
    },
  });
</script>

<style lang="less" scoped>
  .dictionary-authorization {
    .active {
      background: @primary-2 !important;
    }
    display: flex;
    flex-direction: column;
    height: 100%;
    padding: 0 20px;
    border: 1px solid #d7d7d7;
    background: #edf0f4;
    justify-content: space-between;
    align-items: start;
    .footer {
      height: 0px;
      min-height: 70px;
      .btn {
        margin-right: 15px;
        margin-top: 20px;
      }
    }
    .content {
      padding-top: 20px;
      flex: '1';
      height: 100%;
      width: 100%;
      display: flex;
      flex-direction: column;
      overflow-y: auto;
      &::-webkit-scrollbar {
        display: none;
      }
      .top {
        padding-left: 16px;
        width: 100%;
        height: 50px;
        background: #ffffff;
        line-height: 50px;
      }
      .warp {
        flex: 1;
        margin-top: 8px;
        display: flex;
        .left {
          display: flex;
          flex-direction: column;
          height: 100%;
          width: 300px;
          margin-right: 8px;
          .title {
            height: 40px;
            background: #fff;
            line-height: 40px;
            text-align: center;
            margin-bottom: 2px;
          }
          .panel {
            flex: 1;
            background: #fff;
            padding: 16px;
          }
        }
        .middle {
          display: flex;
          flex-direction: column;
          height: 100%;
          width: 300px;
          margin-right: 8px;
          .title {
            height: 40px;
            background: #fff;
            line-height: 40px;
            text-align: center;
            margin-bottom: 2px;
          }
          .list {
            position: relative;
            background: #fff;
            flex: 1;
            // overflow-y: auto;hover
            // &::-webkit-scrollbar {
            //   display: none;
            // }
            .list-tiem {
              height: 30px;
              line-height: 30px;
              padding-left: 8px;
              border-top: 1px solid #e6e6e6;
              border-bottom: 1px solid #e6e6e6;
              margin: 0 -1px -1px 0;
              &:nth-of-type(2n) {
                background: #f9f9f9;
              }
              &:hover {
                cursor: pointer;
              }
            }
            .null {
              position: absolute;
              left: 50%;
              top: 50%;
              transform: translate(-50%, -50%);
            }
          }
        }
        .right {
          flex: 1;
          display: flex;
          flex-direction: column;
          height: 100%;
          .title {
            height: 40px;
            background: #fff;
            line-height: 40px;
            text-align: center;
            margin-bottom: 2px;
          }
          .panel {
            position: relative;
            flex: 1;
            background: #fff;
            .list-tiem {
              position: relative;
              height: 30px;
              line-height: 30px;
              padding-left: 8px;
              &:nth-of-type(2n) {
                background: #f9f9f9;
              }
              border-top: 1px solid #e6e6e6;
              border-bottom: 1px solid #e6e6e6;
              margin: 0 -1px -1px 0;
              &:hover {
                cursor: pointer;
              }
              .word {
                position: absolute;
                left: 32px;
                padding-left: 8px;
                top: 0;
                height: 30px;
                z-index: 1;
                border-left: 1px solid #e6e6e6;
              }
            }
            .null {
              position: absolute;
              left: 50%;
              top: 50%;
              transform: translate(-50%, -50%);
            }
          }
        }
      }
    }
  }
</style>
